-
Revision
-
+ {% if revision['merge'] %}
+
+
+ Merge
+
+
- {% endif %}
+
+ {% endif %}
+
+ {% if revision['url'] is not none %}
+
+ {% endif %}
- {% if revision['history_url'] is not none %}
-
-
Revision Log
-
+ {% if revision['history_url'] is not none %}
+
+ {% endif %}
+
+ {% if revision['history_context_url'] is not none %}
+
+
Contextual Revision Log
+
+
+ {% endif %}
+
+ {% if revision['directory_url'] is not none %}
+
+ {% endif %}
+
+ {% if revision['author'] is not none %}
+
+
Author
+
- {% endif %}
+
+
+ {% endif %}
- {% if revision['history_context_url'] is not none %}
-
-
Contextual Revision Log
-
+ {% if revision['committer'] is not none %}
+
+
Committer
+
- {% endif %}
-
- {% if revision['directory_url'] is not none %}
-
- {% endif %}
+
+
+
Committer Date
+
{{ revision['committer_date'] }}
+
+ {% endif %}
- {% if revision['author'] is not none %}
-
-
- {% endif %}
+ {% if revision['message'] is not none %}
+
+
Message
+
{{ revision['message'] }}
+
+ {% elif revision['message_encoding_failed'] %}
+
+ {% else %}
+
+
Message
+
No message found.
+
+ {% endif %}
- {% if revision['committer'] is not none %}
-
-
-
Committer Date
-
{{ revision['committer_date'] }}
-
- {% endif %}
+ {% for key in revision.keys() %}
+ {% if key in ['type', 'synthetic'] and key not in ['decoding_failures'] and revision[key] is not none %}
+
+ {% endif %}
+ {% endfor %}
- {% if revision['message'] is not none %}
-
-
Message
-
{{ revision['message'] }}
-
- {% elif revision['message_encoding_failed'] %}
-
-
Message
-
No message found.
-
- {% endif %}
-
- {% for key in revision.keys() %}
- {% if key in ['type', 'synthetic'] and key not in ['decoding_failures'] and revision[key] is not none %}
-
- {% endif %}
+ {% for key in ['children_urls', 'parent_urls'] %}
+ {% if revision[key] is not none %}
+
+
{{ key }}
+ {% for link in revision[key] %}
+
{% endfor %}
- {% for key in ['parent_urls', 'children_urls'] %}
- {% if revision[key] is not none %}
-
-
{{ key }}
- {% for link in revision[key] %}
-
- {% endfor %}
-
- {% endif %}
- {% endfor %}
- {% if 'decoding_failures' in revision %}
-
-
(some decoding errors occurred)
-
- {% endif %}
-
+ {% endif %}
+ {% endfor %}
+
+ {% if 'decoding_failures' in revision %}
+
+
(some decoding errors occurred)
+
+ {% endif %}
{% endfor %}
-
-{% endif %}
-
+
+ {% if next_revs_url is not none %}
+
+
+ Next revisions
+
+
+
+ {% endif %}
+ {% endif %}
+
+
{% endblock %}
diff --git a/swh/web/ui/tests/test_converters.py b/swh/web/ui/tests/test_converters.py
--- a/swh/web/ui/tests/test_converters.py
+++ b/swh/web/ui/tests/test_converters.py
@@ -344,6 +344,122 @@
'309d36484e7edf7bb912'
}]
},
+ 'merge': True
+ }
+
+ # when
+ actual_revision = converters.from_revision(revision_input)
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
+
+ @istest
+ def from_revision_nomerge(self):
+ revision_input = {
+ 'id': hashutil.hex_to_hash(
+ '18d8be353ed3480476f032475e7c233eff7371d5'),
+ 'parents': [
+ hashutil.hex_to_hash(
+ '29d8be353ed3480476f032475e7c244eff7371d5')
+ ]
+ }
+
+ expected_revision = {
+ 'id': '18d8be353ed3480476f032475e7c233eff7371d5',
+ 'parents': [
+ '29d8be353ed3480476f032475e7c244eff7371d5'
+ ],
+ 'merge': False
+ }
+
+ # when
+ actual_revision = converters.from_revision(revision_input)
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
+
+ @istest
+ def from_revision_noparents(self):
+ revision_input = {
+ 'id': hashutil.hex_to_hash(
+ '18d8be353ed3480476f032475e7c233eff7371d5'),
+ 'directory': hashutil.hex_to_hash(
+ '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
+ 'author': {
+ 'name': b'Software Heritage',
+ 'fullname': b'robot robot@softwareheritage.org',
+ 'email': b'robot@softwareheritage.org',
+ },
+ 'committer': {
+ 'name': b'Software Heritage',
+ 'fullname': b'robot robot@softwareheritage.org',
+ 'email': b'robot@softwareheritage.org',
+ },
+ 'message': b'synthetic revision message',
+ 'date': {
+ 'timestamp': datetime.datetime(
+ 2000, 1, 17, 11, 23, 54,
+ tzinfo=datetime.timezone.utc).timestamp(),
+ 'offset': 0,
+ 'negative_utc': False,
+ },
+ 'committer_date': {
+ 'timestamp': datetime.datetime(
+ 2000, 1, 17, 11, 23, 54,
+ tzinfo=datetime.timezone.utc).timestamp(),
+ 'offset': 0,
+ 'negative_utc': False,
+ },
+ 'synthetic': True,
+ 'type': 'tar',
+ 'children': [
+ hashutil.hex_to_hash(
+ '123546353ed3480476f032475e7c244eff7371d5'),
+ ],
+ 'metadata': {
+ 'original_artifact': [{
+ 'archive_type': 'tar',
+ 'name': 'webbase-5.7.0.tar.gz',
+ 'sha1': '147f73f369733d088b7a6fa9c4e0273dcd3c7ccd',
+ 'sha1_git': '6a15ea8b881069adedf11feceec35588f2cfe8f1',
+ 'sha256': '401d0df797110bea805d358b85bcc1ced29549d3d73f'
+ '309d36484e7edf7bb912',
+
+ }]
+ },
+ }
+
+ expected_revision = {
+ 'id': '18d8be353ed3480476f032475e7c233eff7371d5',
+ 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
+ 'author': {
+ 'name': 'Software Heritage',
+ 'fullname': 'robot robot@softwareheritage.org',
+ 'email': 'robot@softwareheritage.org',
+ },
+ 'committer': {
+ 'name': 'Software Heritage',
+ 'fullname': 'robot robot@softwareheritage.org',
+ 'email': 'robot@softwareheritage.org',
+ },
+ 'message': 'synthetic revision message',
+ 'date': "2000-01-17T11:23:54+00:00",
+ 'committer_date': "2000-01-17T11:23:54+00:00",
+ 'children': [
+ '123546353ed3480476f032475e7c244eff7371d5'
+ ],
+ 'type': 'tar',
+ 'synthetic': True,
+ 'metadata': {
+ 'original_artifact': [{
+ 'archive_type': 'tar',
+ 'name': 'webbase-5.7.0.tar.gz',
+ 'sha1': '147f73f369733d088b7a6fa9c4e0273dcd3c7ccd',
+ 'sha1_git': '6a15ea8b881069adedf11feceec35588f2cfe8f1',
+ 'sha256': '401d0df797110bea805d358b85bcc1ced29549d3d73f'
+ '309d36484e7edf7bb912'
+ }]
+ }
}
# when
@@ -445,6 +561,7 @@
'309d36484e7edf7bb912'
}]
},
+ 'merge': True
}
# when
diff --git a/swh/web/ui/tests/test_service.py b/swh/web/ui/tests/test_service.py
--- a/swh/web/ui/tests/test_service.py
+++ b/swh/web/ui/tests/test_service.py
@@ -14,6 +14,39 @@
from swh.web.ui.tests import test_app
+REVISION_ID_BIN = hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5')
+REVISION_ID = '18d8be353ed3480476f032475e7c233eff7371d5'
+DIRECTORY_ID_BIN = hex_to_hash('7834ef7e7c357ce2af928115c6c6a42b7e2a44e6')
+DIRECTORY_ID = '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'
+AUTHOR_ID_BIN = {
+ 'name': b'bill & boule',
+ 'email': b'bill@boule.org',
+}
+AUTHOR_ID = {
+ 'name': 'bill & boule',
+ 'email': 'bill@boule.org',
+}
+COMMITTER_ID_BIN = {
+ 'name': b'boule & bill',
+ 'email': b'boule@bill.org',
+}
+COMMITTER_ID = {
+ 'name': 'boule & bill',
+ 'email': 'boule@bill.org',
+}
+SAMPLE_DATE_RAW = {
+ 'timestamp': datetime.datetime(
+ 2000, 1, 17, 11, 23, 54,
+ tzinfo=datetime.timezone.utc,
+ ).timestamp(),
+ 'offset': 0,
+ 'negative_utc': False,
+}
+SAMPLE_DATE = '2000-01-17T11:23:54+00:00'
+SAMPLE_MESSAGE_BIN = b'elegant fix for bug 31415957'
+SAMPLE_MESSAGE = 'elegant fix for bug 31415957'
+
+
class ServiceTestCase(test_app.SWHApiTestCase):
@patch('swh.web.ui.service.backend')
@@ -574,6 +607,7 @@
'parents': [],
'children': [hash_to_hex(b'999'), hash_to_hex(b'777')],
'directory': hash_to_hex(b'278'),
+ 'merge': False
})
mock_query.parse_hash_with_algorithms_or_throws.assert_has_calls(
@@ -646,6 +680,7 @@
'parents': [],
'children': [hash_to_hex(b'999'), hash_to_hex(b'777')],
'directory': hash_to_hex(b'278'),
+ 'merge': False
})
mock_query.parse_hash_with_algorithms_or_throws.assert_called_once_with( # noqa
@@ -953,34 +988,13 @@
def lookup_revision(self, mock_backend):
# given
mock_backend.revision_get = MagicMock(return_value={
- 'id': hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
- 'message': b'elegant fix for bug 31415957',
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
+ 'id': REVISION_ID_BIN,
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
+ 'message': SAMPLE_MESSAGE_BIN,
+ 'date': SAMPLE_DATE_RAW,
+ 'committer_date': SAMPLE_DATE_RAW,
'synthetic': False,
'type': 'git',
'parents': [],
@@ -989,31 +1003,26 @@
# when
actual_revision = service.lookup_revision(
- '18d8be353ed3480476f032475e7c233eff7371d5')
+ REVISION_ID)
# then
self.assertEqual(actual_revision, {
- 'id': '18d8be353ed3480476f032475e7c233eff7371d5',
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
- 'author': {
- 'name': 'bill & boule',
- 'email': 'bill@boule.org',
- },
- 'committer': {
- 'name': 'boule & bill',
- 'email': 'boule@bill.org',
- },
- 'message': 'elegant fix for bug 31415957',
- 'date': "2000-01-17T11:23:54+00:00",
- 'committer_date': "2000-01-17T11:23:54+00:00",
+ 'id': REVISION_ID,
+ 'directory': DIRECTORY_ID,
+ 'author': AUTHOR_ID,
+ 'committer': COMMITTER_ID,
+ 'message': SAMPLE_MESSAGE,
+ 'date': SAMPLE_DATE,
+ 'committer_date': SAMPLE_DATE,
'synthetic': False,
'type': 'git',
'parents': [],
'metadata': [],
+ 'merge': False
})
mock_backend.revision_get.assert_called_with(
- hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'))
+ REVISION_ID_BIN)
@patch('swh.web.ui.service.backend')
@istest
@@ -1021,33 +1030,12 @@
# given
stub_rev = {
'id': hex_to_hash('123456'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
'message': b'elegant fix for bug \xff',
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
+ 'date': SAMPLE_DATE_RAW,
+ 'committer_date': SAMPLE_DATE_RAW,
'synthetic': False,
'type': 'git',
'parents': [],
@@ -1057,66 +1045,40 @@
# when
actual_revision = service.lookup_revision(
- '18d8be353ed3480476f032475e7c233eff7371d5')
+ REVISION_ID)
# then
self.assertEqual(actual_revision, {
'id': '123456',
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
- 'author': {
- 'name': 'bill & boule',
- 'email': 'bill@boule.org',
- },
- 'committer': {
- 'name': 'boule & bill',
- 'email': 'boule@bill.org',
- },
+ 'directory': DIRECTORY_ID,
+ 'author': AUTHOR_ID,
+ 'committer': COMMITTER_ID,
'message': None,
'message_decoding_failed': True,
- 'date': "2000-01-17T11:23:54+00:00",
- 'committer_date': "2000-01-17T11:23:54+00:00",
+ 'date': SAMPLE_DATE,
+ 'committer_date': SAMPLE_DATE,
'synthetic': False,
'type': 'git',
'parents': [],
'metadata': [],
+ 'merge': False
})
mock_backend.revision_get.assert_called_with(
- hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'))
+ REVISION_ID_BIN)
@patch('swh.web.ui.service.backend')
@istest
def lookup_revision_msg_ok(self, mock_backend):
# given
mock_backend.revision_get.return_value = {
- 'id': hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
- 'message': b'elegant fix for bug 31415957',
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
+ 'id': REVISION_ID_BIN,
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
+ 'message': SAMPLE_MESSAGE_BIN,
+ 'date': SAMPLE_DATE_RAW,
+ 'committer_date': SAMPLE_DATE_RAW,
'synthetic': False,
'type': 'git',
'parents': [],
@@ -1125,45 +1087,24 @@
# when
rv = service.lookup_revision_message(
- '18d8be353ed3480476f032475e7c233eff7371d5')
+ REVISION_ID)
# then
- self.assertEquals(rv, {'message': b'elegant fix for bug 31415957'})
+ self.assertEquals(rv, {'message': SAMPLE_MESSAGE_BIN})
mock_backend.revision_get.assert_called_with(
- hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'))
+ REVISION_ID_BIN)
@patch('swh.web.ui.service.backend')
@istest
def lookup_revision_msg_absent(self, mock_backend):
# given
mock_backend.revision_get.return_value = {
- 'id': hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
+ 'id': REVISION_ID_BIN,
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
+ 'date': SAMPLE_DATE_RAW,
+ 'committer_date': SAMPLE_DATE_RAW,
'synthetic': False,
'type': 'git',
'parents': [],
@@ -1173,11 +1114,11 @@
# when
with self.assertRaises(NotFoundExc) as cm:
service.lookup_revision_message(
- '18d8be353ed3480476f032475e7c233eff7371d5')
+ REVISION_ID)
# then
mock_backend.revision_get.assert_called_with(
- hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'))
+ REVISION_ID_BIN)
self.assertEqual(cm.exception.args[0], 'No message for revision '
'with sha1_git '
'18d8be353ed3480476f032475e7c233eff7371d5.')
@@ -1191,11 +1132,11 @@
# when
with self.assertRaises(NotFoundExc) as cm:
service.lookup_revision_message(
- '18d8be353ed3480476f032475e7c233eff7371d5')
+ REVISION_ID)
# then
mock_backend.revision_get.assert_called_with(
- hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'))
+ REVISION_ID_BIN)
self.assertEqual(cm.exception.args[0], 'Revision with sha1_git '
'18d8be353ed3480476f032475e7c233eff7371d5 '
'not found.')
@@ -1205,37 +1146,19 @@
def lookup_revision_multiple(self, mock_backend):
# given
- sha1_bin = '18d8be353ed3480476f032475e7c233eff7371d5'
+ sha1_bin = REVISION_ID
sha1_other = 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'
stub_revisions = [
{
'id': hex_to_hash(sha1_bin),
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
- 'message': b'elegant fix for bug 31415957',
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc).timestamp(),
- 'offset': 0,
- 'negative_utc': False
- },
+ 'directory': DIRECTORY_ID,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
+ 'message': SAMPLE_MESSAGE_BIN,
+ 'date': SAMPLE_DATE_RAW,
'date_offset': 0,
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc).timestamp(),
- 'offset': 0,
- 'negative_utc': False
- },
+ 'committer_date': SAMPLE_DATE_RAW,
'committer_date_offset': 0,
'synthetic': False,
'type': 'git',
@@ -1287,24 +1210,19 @@
self.assertEqual(list(actual_revisions), [
{
'id': sha1_bin,
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
- 'author': {
- 'name': 'bill & boule',
- 'email': 'bill@boule.org',
- },
- 'committer': {
- 'name': 'boule & bill',
- 'email': 'boule@bill.org',
- },
- 'message': 'elegant fix for bug 31415957',
- 'date': '2000-01-17T11:23:54+00:00',
+ 'directory': DIRECTORY_ID,
+ 'author': AUTHOR_ID,
+ 'committer': COMMITTER_ID,
+ 'message': SAMPLE_MESSAGE,
+ 'date': SAMPLE_DATE,
'date_offset': 0,
- 'committer_date': '2000-01-17T11:23:54+00:00',
+ 'committer_date': SAMPLE_DATE,
'committer_date_offset': 0,
'synthetic': False,
'type': 'git',
'parents': [],
'metadata': [],
+ 'merge': False
},
{
'id': sha1_other,
@@ -1326,13 +1244,14 @@
'type': 'git',
'parents': [],
'metadata': [],
+ 'merge': False
}
])
self.assertEqual(
list(mock_backend.revision_get_multiple.call_args[0][0]),
[hex_to_hash(
- '18d8be353ed3480476f032475e7c233eff7371d5'),
+ REVISION_ID),
hex_to_hash(
'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc')])
@@ -1340,7 +1259,7 @@
@istest
def lookup_revision_multiple_none_found(self, mock_backend):
# given
- sha1_bin = '18d8be353ed3480476f032475e7c233eff7371d5'
+ sha1_bin = REVISION_ID
sha1_other = 'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'
mock_backend.revision_get_multiple.return_value = []
@@ -1354,7 +1273,7 @@
self.assertEqual(
list(mock_backend.revision_get_multiple.call_args[0][0]),
[hex_to_hash(
- '18d8be353ed3480476f032475e7c233eff7371d5'),
+ REVISION_ID),
hex_to_hash(
'adc83b19e793491b1c6ea0fd8b46cd9f32e592fc')])
@@ -1364,33 +1283,12 @@
# given
stub_revision_log = [{
'id': hex_to_hash('28d8be353ed3480476f032475e7c233eff7371d5'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
- 'message': b'elegant fix for bug 31415957',
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
+ 'message': SAMPLE_MESSAGE_BIN,
+ 'date': SAMPLE_DATE_RAW,
+ 'committer_date': SAMPLE_DATE_RAW,
'synthetic': False,
'type': 'git',
'parents': [],
@@ -1405,22 +1303,17 @@
# then
self.assertEqual(list(actual_revision), [{
'id': '28d8be353ed3480476f032475e7c233eff7371d5',
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
- 'author': {
- 'name': 'bill & boule',
- 'email': 'bill@boule.org',
- },
- 'committer': {
- 'name': 'boule & bill',
- 'email': 'boule@bill.org',
- },
- 'message': 'elegant fix for bug 31415957',
- 'date': "2000-01-17T11:23:54+00:00",
- 'committer_date': "2000-01-17T11:23:54+00:00",
+ 'directory': DIRECTORY_ID,
+ 'author': AUTHOR_ID,
+ 'committer': COMMITTER_ID,
+ 'message': SAMPLE_MESSAGE,
+ 'date': SAMPLE_DATE,
+ 'committer_date': SAMPLE_DATE,
'synthetic': False,
'type': 'git',
'parents': [],
'metadata': [],
+ 'merge': False
}])
mock_backend.revision_log.assert_called_with(
@@ -1432,33 +1325,12 @@
# given
stub_revision_log = [{
'id': hex_to_hash('28d8be353ed3480476f032475e7c233eff7371d5'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
- 'author': {
- 'name': b'bill & boule',
- 'email': b'bill@boule.org',
- },
- 'committer': {
- 'name': b'boule & bill',
- 'email': b'boule@bill.org',
- },
- 'message': b'elegant fix for bug 31415957',
- 'date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
- 'committer_date': {
- 'timestamp': datetime.datetime(
- 2000, 1, 17, 11, 23, 54,
- tzinfo=datetime.timezone.utc,
- ).timestamp(),
- 'offset': 0,
- 'negative_utc': False,
- },
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': AUTHOR_ID_BIN,
+ 'committer': COMMITTER_ID_BIN,
+ 'message': SAMPLE_MESSAGE_BIN,
+ 'date': SAMPLE_DATE_RAW,
+ 'committer_date': SAMPLE_DATE_RAW,
'synthetic': False,
'type': 'git',
'parents': [],
@@ -1473,22 +1345,17 @@
# then
self.assertEqual(list(actual_log), [{
'id': '28d8be353ed3480476f032475e7c233eff7371d5',
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
- 'author': {
- 'name': 'bill & boule',
- 'email': 'bill@boule.org',
- },
- 'committer': {
- 'name': 'boule & bill',
- 'email': 'boule@bill.org',
- },
- 'message': 'elegant fix for bug 31415957',
- 'date': "2000-01-17T11:23:54+00:00",
- 'committer_date': "2000-01-17T11:23:54+00:00",
+ 'directory': DIRECTORY_ID,
+ 'author': AUTHOR_ID,
+ 'committer': COMMITTER_ID,
+ 'message': SAMPLE_MESSAGE,
+ 'date': SAMPLE_DATE,
+ 'committer_date': SAMPLE_DATE,
'synthetic': False,
'type': 'git',
'parents': [],
'metadata': [],
+ 'merge': False
}])
mock_backend.revision_log_by.assert_called_with(
@@ -1756,8 +1623,7 @@
# given
stub_rev = {
'id': hex_to_hash('28d8be353ed3480476f032475e7c233eff7371d5'),
- 'directory': hex_to_hash(
- '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'),
+ 'directory': DIRECTORY_ID_BIN,
'author': {
'name': b'ynot',
'email': b'ynot@blah.org',
@@ -1785,7 +1651,7 @@
expected_rev = {
'id': '28d8be353ed3480476f032475e7c233eff7371d5',
- 'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
+ 'directory': DIRECTORY_ID,
'author': {
'name': 'ynot',
'email': 'ynot@blah.org',
@@ -1811,6 +1677,81 @@
@patch('swh.web.ui.service.backend')
@istest
+ def lookup_revision_by_nomerge(self, mock_backend):
+ # given
+ stub_rev = {
+ 'id': hex_to_hash('28d8be353ed3480476f032475e7c233eff7371d5'),
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': {
+ 'name': b'ynot',
+ 'email': b'ynot@blah.org',
+ },
+ 'parents': [
+ hex_to_hash('adc83b19e793491b1c6ea0fd8b46cd9f32e592fc')]
+ }
+
+ expected_rev = {
+ 'id': '28d8be353ed3480476f032475e7c233eff7371d5',
+ 'directory': DIRECTORY_ID,
+ 'author': {
+ 'name': 'ynot',
+ 'email': 'ynot@blah.org',
+ },
+ 'parents': ['adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'],
+ 'merge': False
+ }
+
+ mock_backend.revision_get_by.return_value = stub_rev
+
+ # when
+ actual_revision = service.lookup_revision_by(10, 'master2', 'some-ts')
+
+ # then
+ self.assertEquals(actual_revision, expected_rev)
+
+ mock_backend.revision_get_by(1, 'master2', 'some-ts')
+
+ @patch('swh.web.ui.service.backend')
+ @istest
+ def lookup_revision_by_merge(self, mock_backend):
+ # given
+ stub_rev = {
+ 'id': hex_to_hash('28d8be353ed3480476f032475e7c233eff7371d5'),
+ 'directory': DIRECTORY_ID_BIN,
+ 'author': {
+ 'name': b'ynot',
+ 'email': b'ynot@blah.org',
+ },
+ 'parents': [
+ hex_to_hash('adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'),
+ hex_to_hash('adc83b19e793491b1c6db0fd8b46cd9f32e592fc')
+ ]
+ }
+
+ expected_rev = {
+ 'id': '28d8be353ed3480476f032475e7c233eff7371d5',
+ 'directory': DIRECTORY_ID,
+ 'author': {
+ 'name': 'ynot',
+ 'email': 'ynot@blah.org',
+ },
+ 'parents': ['adc83b19e793491b1c6ea0fd8b46cd9f32e592fc',
+ 'adc83b19e793491b1c6db0fd8b46cd9f32e592fc'],
+ 'merge': True
+ }
+
+ mock_backend.revision_get_by.return_value = stub_rev
+
+ # when
+ actual_revision = service.lookup_revision_by(10, 'master2', 'some-ts')
+
+ # then
+ self.assertEquals(actual_revision, expected_rev)
+
+ mock_backend.revision_get_by(1, 'master2', 'some-ts')
+
+ @patch('swh.web.ui.service.backend')
+ @istest
def lookup_revision_with_context_by_ko(self, mock_backend):
# given
mock_backend.revision_get_by.return_value = None
diff --git a/swh/web/ui/tests/views/test_api.py b/swh/web/ui/tests/views/test_api.py
--- a/swh/web/ui/tests/views/test_api.py
+++ b/swh/web/ui/tests/views/test_api.py
@@ -1443,10 +1443,10 @@
'id': '18d8be353ed3480476f032475e7c233eff7371d5',
'url': '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5/',
'history_url': '/api/1/revision/18d8be353ed3480476f032475e7c233ef'
- 'f7371d5/log/',
+ 'f7371d5/log/',
'directory': '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6',
'directory_url': '/api/1/directory/7834ef7e7c357ce2af928115c6c6a'
- '42b7e2a44e6/',
+ '42b7e2a44e6/',
'author_name': 'Software Heritage',
'author_email': 'robot@softwareheritage.org',
'committer_name': 'Software Heritage',
@@ -1465,6 +1465,11 @@
'synthetic': True,
}]
+ expected_response = {
+ 'revisions': expected_revisions,
+ 'next_revs_url': None
+ }
+
# when
rv = self.app.get('/api/1/revision/8834ef7e7c357ce2af928115c6c6a42'
'b7e2a44e6/log/')
@@ -1474,10 +1479,44 @@
self.assertEquals(rv.mimetype, 'application/json')
response_data = json.loads(rv.data.decode('utf-8'))
- self.assertEquals(response_data, expected_revisions)
+ self.assertEquals(response_data, expected_response)
mock_service.lookup_revision_log.assert_called_once_with(
- '8834ef7e7c357ce2af928115c6c6a42b7e2a44e6', 100)
+ '8834ef7e7c357ce2af928115c6c6a42b7e2a44e6', 26)
+
+ @patch('swh.web.ui.views.api.service')
+ @istest
+ def api_revision_log_with_next(self, mock_service):
+ # given
+ stub_revisions = []
+ for i in range(27):
+ stub_revisions.append({'id': i})
+
+ mock_service.lookup_revision_log.return_value = stub_revisions[:26]
+
+ expected_revisions = [x for x in stub_revisions if x['id'] < 25]
+ for e in expected_revisions:
+ e['url'] = '/api/1/revision/%s/' % e['id']
+ e['history_url'] = '/api/1/revision/%s/log/' % e['id']
+
+ expected_response = {
+ 'revisions': expected_revisions,
+ 'next_revs_url': '/api/1/revision/25/log/'
+ }
+
+ # when
+ rv = self.app.get('/api/1/revision/8834ef7e7c357ce2af928115c6c6a42'
+ 'b7e2a44e6/log/')
+
+ # then
+ self.assertEquals(rv.status_code, 200)
+ self.assertEquals(rv.mimetype, 'application/json')
+
+ response_data = json.loads(rv.data.decode('utf-8'))
+ self.assertEquals(response_data, expected_response)
+
+ mock_service.lookup_revision_log.assert_called_once_with(
+ '8834ef7e7c357ce2af928115c6c6a42b7e2a44e6', 26)
@patch('swh.web.ui.views.api.service')
@istest
@@ -1487,7 +1526,7 @@
# when
rv = self.app.get('/api/1/revision/8834ef7e7c357ce2af928115c6c6a42b7'
- 'e2a44e6/log/?limit=10')
+ 'e2a44e6/log/')
# then
self.assertEquals(rv.status_code, 404)
@@ -1499,7 +1538,7 @@
' 8834ef7e7c357ce2af928115c6c6a42b7e2a44e6 not found.'})
mock_service.lookup_revision_log.assert_called_once_with(
- '8834ef7e7c357ce2af928115c6c6a42b7e2a44e6', 10)
+ '8834ef7e7c357ce2af928115c6c6a42b7e2a44e6', 26)
@patch('swh.web.ui.views.api.service')
@istest
@@ -1536,15 +1575,7 @@
'synthetic': True,
}]
- # when
- rv = self.app.get('/api/1/revision/18d8be353ed3480476f0'
- '32475e7c233eff7371d5/prev/prev-rev/log/')
-
- # then
- self.assertEquals(rv.status_code, 200)
- self.assertEquals(rv.mimetype, 'application/json')
- response_data = json.loads(rv.data.decode('utf-8'))
- self.assertEquals(response_data, [
+ expected_revisions = [
{
'url': '/api/1/revision/'
'7834ef7e7c357ce2af928115c6c6a42b7e2a44e6/',
@@ -1592,10 +1623,25 @@
],
'type': 'tar',
'synthetic': True,
- }])
+ }]
+
+ expected_response = {
+ 'revisions': expected_revisions,
+ 'next_revs_url': None
+ }
+
+ # when
+ rv = self.app.get('/api/1/revision/18d8be353ed3480476f0'
+ '32475e7c233eff7371d5/prev/prev-rev/log/')
+
+ # then
+ self.assertEquals(rv.status_code, 200)
+ self.assertEquals(rv.mimetype, 'application/json')
+ response_data = json.loads(rv.data.decode('utf-8'))
+ self.assertEquals(response_data, expected_response)
mock_service.lookup_revision_log.assert_called_once_with(
- '18d8be353ed3480476f032475e7c233eff7371d5', 100)
+ '18d8be353ed3480476f032475e7c233eff7371d5', 26)
mock_service.lookup_revision_multiple.assert_called_once_with(
['prev-rev'])
diff --git a/swh/web/ui/tests/views/test_browse.py b/swh/web/ui/tests/views/test_browse.py
--- a/swh/web/ui/tests/views/test_browse.py
+++ b/swh/web/ui/tests/views/test_browse.py
@@ -913,27 +913,30 @@
@istest
def browse_revision_log(self, mock_api):
# given
- stub_revisions = [{
- 'id': 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754',
- 'date': 'Sun, 05 Jul 2015 18:01:52 GMT',
- 'committer': {
- 'email': 'torvalds@linux-foundation.org',
- 'name': 'Linus Torvalds'
- },
- 'committer_date': 'Sun, 05 Jul 2015 18:01:52 GMT',
- 'type': 'git',
- 'author': {
- 'email': 'torvalds@linux-foundation.org',
- 'name': 'Linus Torvalds'
- },
- 'message': 'Linux 4.2-rc1\n',
- 'synthetic': False,
- 'directory_url': '/api/1/directory/'
- '2a1dbabeed4dcf1f4a4c441993b2ffc9d972780b/',
- 'parent_url': [
- '/api/1/revision/a585d2b738bfa26326b3f1f40f0f1eda0c067ccf/'
- ],
- }]
+ stub_revisions = {
+ 'revisions': [{
+ 'id': 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754',
+ 'date': 'Sun, 05 Jul 2015 18:01:52 GMT',
+ 'committer': {
+ 'email': 'torvalds@linux-foundation.org',
+ 'name': 'Linus Torvalds'
+ },
+ 'committer_date': 'Sun, 05 Jul 2015 18:01:52 GMT',
+ 'type': 'git',
+ 'author': {
+ 'email': 'torvalds@linux-foundation.org',
+ 'name': 'Linus Torvalds'
+ },
+ 'message': 'Linux 4.2-rc1\n',
+ 'synthetic': False,
+ 'directory_url': '/api/1/directory/'
+ '2a1dbabeed4dcf1f4a4c441993b2ffc9d972780b/',
+ 'parent_url': [
+ '/api/1/revision/a585d2b738bfa26326b3f1f40f0f1eda0c067ccf/'
+ ],
+ }],
+ 'next_revs_url': '/api/1/revision/1234/log/'
+ }
mock_api.api_revision_log.return_value = stub_revisions
# when
@@ -945,6 +948,9 @@
self.assertEqual(self.get_context_variable('sha1_git'), '426')
self.assertTrue(
isinstance(self.get_context_variable('revisions'), map))
+ self.assertEqual(
+ self.get_context_variable('next_revs_url'),
+ '/browse/revision/1234/log/')
self.assertIsNone(self.get_context_variable('message'))
mock_api.api_revision_log.assert_called_once_with('426', None)
diff --git a/swh/web/ui/views/api.py b/swh/web/ui/views/api.py
--- a/swh/web/ui/views/api.py
+++ b/swh/web/ui/views/api.py
@@ -705,7 +705,7 @@
@app.route('/api/1/revision/
/log/')
@app.route('/api/1/revision//prev//log/')
-def api_revision_log(sha1_git, prev_sha1s=None):
+def api_revision_log(sha1_git, prev_sha1s=None, limit=25):
"""Show all revisions (~git log) starting from sha1_git.
The first element returned is the given sha1_git.
@@ -724,26 +724,42 @@
NotFoundExc if the revision is not found.
"""
- limit = int(request.args.get('limit', '100'))
- def lookup_revision_log_with_limit(s, limit=limit):
+ response = {'revisions': None, 'next_revs_url': None}
+ revisions = None
+ next_revs_url = None
+
+ def lookup_revision_log_with_limit(s, limit=limit+1):
return service.lookup_revision_log(s, limit)
error_msg = 'Revision with sha1_git %s not found.' % sha1_git
- rev_backward = _api_lookup(sha1_git,
- lookup_fn=lookup_revision_log_with_limit,
- error_msg_if_not_found=error_msg,
- enrich_fn=utils.enrich_revision)
+ rev_get = _api_lookup(sha1_git,
+ lookup_fn=lookup_revision_log_with_limit,
+ error_msg_if_not_found=error_msg,
+ enrich_fn=utils.enrich_revision)
+
+ if len(rev_get) == limit+1:
+ rev_backward = rev_get[:-1]
+ next_revs_url = url_for('api_revision_log',
+ sha1_git=rev_get[-1]['id'])
+ else:
+ rev_backward = rev_get
if not prev_sha1s: # no nav breadcrumbs, so we're done
- return rev_backward
-
- rev_forward_ids = prev_sha1s.split('/')
- rev_forward = _api_lookup(rev_forward_ids,
- lookup_fn=service.lookup_revision_multiple,
- error_msg_if_not_found=error_msg,
- enrich_fn=utils.enrich_revision)
- return rev_forward + rev_backward
+ revisions = rev_backward
+
+ else:
+ rev_forward_ids = prev_sha1s.split('/')
+ rev_forward = _api_lookup(rev_forward_ids,
+ lookup_fn=service.lookup_revision_multiple,
+ error_msg_if_not_found=error_msg,
+ enrich_fn=utils.enrich_revision)
+ revisions = rev_forward + rev_backward
+
+ response['revisions'] = revisions
+ response['next_revs_url'] = next_revs_url
+
+ return response
@app.route('/api/1/revision'
diff --git a/swh/web/ui/views/browse.py b/swh/web/ui/views/browse.py
--- a/swh/web/ui/views/browse.py
+++ b/swh/web/ui/views/browse.py
@@ -364,8 +364,12 @@
'revisions': []}
try:
- revisions = api.api_revision_log(sha1_git, prev_sha1s)
+ revision_data = api.api_revision_log(sha1_git, prev_sha1s)
+ revisions = revision_data['revisions']
+ next_revs_url = revision_data['next_revs_url']
env['revisions'] = map(utils.prepare_data_for_view, revisions)
+ env['next_revs_url'] = utils.prepare_data_for_view(next_revs_url)
+
except (NotFoundExc, BadInputExc) as e:
env['message'] = str(e)